/*========================================================================
#include <stdio.h>
#   FileName: manage.c
#     Author: lwd
#      Email: lwd_xinghuo@126.com
#   HomePage: 
# LastChange: 2013-04-18 09:56:32
========================================================================*/
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include "public.h"
#include "Process.h"
#include "control.h"
#include "prosync.h"
#include "config.h"

#define PRINT_FUNC \
	do{\
		printf("file:%s func:%s LINE:%d \n",\
				__FILE__, __func__, __LINE__);\
	}while(0)

//time slice
#define TIME_SLICE 3

//控制manage线程中，计时器与信号处理的同步
static pthread_mutex_t pthm = PTHREAD_MUTEX_INITIALIZER;
//控制测试任务的互斥
static pthread_mutex_t tptm = PTHREAD_MUTEX_INITIALIZER;
//控制测试任务与调度任务之间的同步
static pthread_mutex_t smtm = PTHREAD_MUTEX_INITIALIZER;
//当前执行进程的pid
static pid_t pid = -1;		//the pid of current-process

static void weakup(int sig_num)
{
	PRINT_FUNC;
	//在计时到此可以转为测试任务
	//此处之后，再次转为不可转换为测试任务
	//pthread_mutex_lock(&smtm);
	pthread_mutex_unlock(&pthm);
}

static void finished(int sig_num)
{
	PRINT_FUNC;
	//在计时到此可以转为测试任务
	//此处之后，再次转为不可转换为测试任务
	//pthread_mutex_lock(&smtm);
	alarm(0);
	pid = -1;
	delete();
#if 1
	//while there is a process is finished,
	//this function responding
	int r = waitpid( pid, 0, 0);
	pid = 0;	//current-process is finished(destoryed)
	printf("child %d is finished! func:%s LINE:%d\n",
		   	r, __func__, __LINE__);
	pthread_mutex_unlock(&pthm);
	//exit (0);
#endif
}

static void timer(int sec)
{
	PRINT_FUNC;
	//timer: retrun after sec seconds
	signal(SIGALRM, weakup);
	signal(SIGCHLD, finished);
	alarm(sec);
	//解锁，在线程进入计时过程，允许转为测试任务
	//直到计时结束，或者当前任务结束
	//pthread_mutex_unlock(&smtm);
	//线程锁，等待计时结束或者当前进程完成
	pthread_mutex_lock(&pthm);
}

static void testfinish(int sig_num)
{
}

static int testProcesss(char* modeName, char* modeFile, char* dataFile)
{
	//创建测试进程
	pid_t pid = fork();
	printf("modemame = %s\n", modeName);
	if(pid == 0)
	{
		//子进程，调用测试程序（execv），转变为测试进程
		printf("create a test process!\n");
		char* args[3] = { modeName, modeFile, dataFile };
		const Service* s = getServiceInfo(modeName);
		
		execv(s->tpath, args);
	}
	else if(pid > 0)
	{
		//修改信号处理函数，等待此子进程结束
		signal(SIGCHLD, testfinish);
		//父进程，等待测试任务完成
		waitpid(pid, 0, 0);
		//注意：返回结果文件，在线程中调用此函数处执行
		//改会调度时，子进程结束的信号处理函数
		signal(SIGCHLD, finished);
		return 0;
	}
	else
	{
		return 1;
	}
}

//是否可以是读者写者问题，当没有测试进程后，继续执行训练模型任务
int stopCurrent(char* modeName, char* modeFile, char* dataFile)
{
	//线程锁，查看当前是否可以执行测试任务
	pthread_mutex_lock(&smtm);
	//线程锁，阻止其他线程调用本函数
	pthread_mutex_lock(&tptm);
	int sec = 0;
	//stop current process
	if(pid > 0 && kill(pid, SIGUSR1) == 0)
	{
		//当前进程存在，切已停止，记录剩余时间片
		//创建新进程，执行测试任务，
		//等待测试任务结束，
		//如果剩余时间片大于0， 继续执行，
		//如果剩余时间片等于0， 直接执行weakup函数
		sync_P();
		//get the remain time
		//获取剩余时间片
		sec = alarm(0);
		printf("当前进程已经暂停！\n");
		//create test process
		//创建测试进程
		testProcesss(modeName, modeFile, dataFile);
		if(sec > 0)
		{
			//剩余时间片大于0， 继续执行当前任务
			printf("剩余时间片%d\n", sec);
			alarm(sec);
			//allow current process continue to run
			printf("重新开始\n");
			kill(pid, SIGUSR2);
		}
	}
	else 
	{
		//当前没有进程在执行，或者当前进程恰好结束，
		//只需执行完成测试任务即可
		testProcesss(modeName, modeFile, dataFile);
	}
	
	//解锁，允许其他线程调用本函数
	pthread_mutex_unlock(&tptm);
	//解锁，允许调度线程继续执行
	pthread_mutex_unlock(&smtm);
	return 0;
}

#if 1
//
char* ag[5] = { "A", "B", "C", "D", "E" };

static int createProcess(int id)
{
#if 1
	int ret = fork();
	if(ret == 0)
	{
		printf("this is the %dth child process!\n", id);
		char* args[] = { "./func1", ag[id] , "123"};
		
		execv("./src/func1", args);
	}
#endif
	PRINT_FUNC;
	//return id + 1;
	return ret;
}

void *createProcesses(void* arg)
{
	int cpid;
	int i = 0;
	Process p;
	
	printf("this is createProcess function! func:%s line:%d\n", __func__, __LINE__);
	sleep(1);
	for(i = 0; i < 5; i++)
	{
		cpid = createProcess(i);
		if(cpid > 0)
		{
			p.pid = cpid;
			p.jid = i;
			p.state = WAIT;
			
			sleep(1);
			add_new(p);
		}
		else
		{
			printf("create child-process failed! func:%s line:%d\n",\
					__func__, __LINE__);
		}
	}
#if 1
	for(i = 0; i < 5; i++)
	{
		p.jid = i;
		search(&p);
		printf("search: pid = %d jid = %d state = %d\n", \
				p.pid, p.jid, p.state);
	}
#endif
	pthread_exit(0);
	//return 0;
}
#endif

static inline int run(pid_t pid)
{
	PRINT_FUNC;
	return kill(pid, SIGUSR2);
	//return 0;
}

static inline void stop(pid_t pid)
{
	PRINT_FUNC;
	if(pid >= 0)		//if current-process is not finished(is exist)
	{
		//send msg to child(pid)
		kill(pid, SIGUSR1);
		
		sync_P();
		//waitting for child release its resource
		//signal(SIGUSR1, update_processinfo);
		//pause();
		Message msg;
		bzero(&msg, sizeof(msg));
		int ret = recvMSG(&msg);
		//int ret = recvMSG();
		//printf("\t\t\tret = %d", ret);
		if(!ret)
		{
			printf("recv msg successfully! func:%s line:%d\n",\
				__func__, __LINE__);
		}
		sleep(1);
		//add the current-process into process-list
		add_tail(msg.rate);
		pid = -1;
	}
}

void *manage(void* arg)
{
	
	printf("this is manage function! func:%s line:%d\n", __func__, __LINE__);
	
	if(init_msg())
	{
		printf("ERROR:init msg_queue! FILE_%s LINE:%d\n", __FILE__, __LINE__);
	}
	
	//pthread lock to implement sync
	//线程锁，此处调用，让资源数记为0，实现同步
	pthread_mutex_lock(&pthm);
	//线程锁，此处调用，让资源为0，
	//实现调度线程与socket通信线程中到测试任务的同步
	//此处到选择当前要执行任务之前，不允许转为测试任务
	//pthread_mutex_lock(&smtm);
	int i = 0;
	while(1)
	{
		printf("while time %d\n", i++);
		//if queue is NULL, wait
		//pid is a gobal variable
		//选择一个任务，如果队列为空，等待
		pid = choose();
		while(pid< 0) 
		{
			//解线程锁，允许执行调度任务
			//pthread_mutex_unlock(&smtm);
			//
			//解锁与上锁之间 允许 中断线程，执行测试任务
			//防止，当任务队列一直为空时，测试任务一直等待
			//
			//线程锁，在执行choose的同时，不能转为测试任务
			//如果队列不为空，可以得到一个当前任务
			//此处到进入计时之前不允许转为测试任务
			//pthread_mutex_lock(&smtm);
			pid = choose();
		}
		
		printf("\tthe choosed process pid = %d\n", pid);
		
		if(run(pid))
		{
			printf("kill signal to child %d error!\n", pid );
			continue;
		}
		timer(TIME_SLICE);
		printf("timer over! \n");
		stop(pid);
	}
}


